package ve.com.wayoyo.wuml_case.DibujoDiagramas;

import ve.com.wayoyo.wuml_case.Painter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;

public class CompConector implements Cloneable {

	// Constantes
	public static final int ORIENTATION_TOP = 1;
	public static final int ORIENTATION_BOTTOM = 2;
	public static final int ORIENTATION_LEFT = 3;
	public static final int ORIENTATION_RIGHT = 4;
	public static final int ORIENTATION_INNER_TOP = 5;
	public static final int ORIENTATION_INNER_BOTTOM = 6;
	public static final int ORIENTATION_INNER_LEFT = 7;
	public static final int ORIENTATION_INNER_RIGHT = 8;
	private static final int TOUCH_HITBOX_SIZE = 15;
	private static final int RECURSIVE_SPAN = 40;

	// Estados
	public static final int IDLE_STATE = 1;
	public static final int SELECTED_STATE = 2;
	public static final int PATH_STATE = 3;

	// Tipos de Linea
	public static final int NORMAL_TYPE = 0;
	public static final int DASHED_TYPE = 1;
	public static final int FATHER_SIDE_DASHED = 2; // Solo la mitad
													// correspondiente al padre
													// estara punteada.
	public static final int CHILD_SIDE_DASHED = 3; // Solo la mitad
													// correspondiente al hijo
													// estara punteada.

	protected int _fatherId;
	protected int _childId;
	protected Point _fatherCenter;
	protected Point _childCenter;
	protected int _childQuadrant;
	protected int _fatherArrowType;
	protected int _childArrowType;
	protected int _fatherOrientation = 0;
	protected int _childOrientation = 0;
	protected int _currentState;
	protected int _currentLineType;
	protected Path[] _linePath;
	protected String _fatherCardenalityLeft = "1";
	protected String _fatherCardenalityRight = "1";
	protected String _childCardenalityLeft = "1";
	protected String _childCardenalityRight = "*";
	protected boolean _haveCost = false;
	protected float costo;

	// Puntos para dibujar la linea
	protected Point[] _points = new Point[5];

	// Cantidad de puntos
	protected int _numberOfPoints;
	
	public CompConector clone(){
		try {
			return (CompConector) super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	// Tipos de Terminaciones de los conectores
	public static class _arrowType {
		public static final int Asociacion = 0;// dashed
		public static final int Herencia = 1;// generalizacion y realizacion
		public static final int Asociacion_Directa = 2;// dependencia
		public static final int Agregacion = 3;
		public static final int Composicion = 4;
		public static final int PataDeGallo_PK = 5;
		public static final int PataDeGallo = 6;
		public static final int Union_Simple = 7;
		public static final int Flecha_Llena = 8;
		public static final int Asociacion_FK = 9;
	}

	private int _fatherConectorPort = -1;
	private int _childConectorPort = -1;

	// Pinters
	protected Paint _normalLinePaint;

	public int get_fatherConectorPort() {
		return _fatherConectorPort;
	}

	public void setCosto(float costo) {
		this.costo = costo;
		if (!_haveCost) {
			_haveCost = true;
		}
	}

	public boolean is_haveCost() {
		return _haveCost;
	}

	public void set_haveCost(boolean _haveCost) {
		this._haveCost = _haveCost;
	}

	public float getCosto() {
		return costo;
	}

	public void set_fatherConectorPort(int _fatherConectorPort) {
		this._fatherConectorPort = _fatherConectorPort;
	}

	public int get_childConectorPort() {
		return _childConectorPort;
	}

	public void set_childConectorPort(int _childConectorPort) {
		this._childConectorPort = _childConectorPort;
	}

	public CompConector(int fatherID, int childID) {
		super();
		_fatherId = fatherID;
		_childId = childID;
	}

	public String get_fatherCardenalityLeft() {
		return _fatherCardenalityLeft;
	}

	public void set_fatherCardenalityLeft(String _fatherCardenalityLeft) {
		this._fatherCardenalityLeft = _fatherCardenalityLeft;
	}

	public String get_fatherCardenalityRight() {
		return _fatherCardenalityRight;
	}

	public void set_fatherCardenalityRight(String _fatherCardenalityRight) {
		this._fatherCardenalityRight = _fatherCardenalityRight;
	}

	public String get_childCardenalityLeft() {
		return _childCardenalityLeft;
	}

	public void set_childCardenalityLeft(String _childCardenalityLeft) {
		this._childCardenalityLeft = _childCardenalityLeft;
	}

	public String get_childCardenalityRight() {
		return _childCardenalityRight;
	}

	public void set_childCardenalityRight(String _childCardenalityRight) {
		this._childCardenalityRight = _childCardenalityRight;
	}

	public void set_childQuadrant(int _childQuadrant) {
		this._childQuadrant = _childQuadrant;
	}

	public void set_fatherOrientation(int _fatherOrientation) {
		this._fatherOrientation = _fatherOrientation;
	}

	public void set_childCenter(Point _childCenter) {
		this._childCenter = _childCenter;
	}

	public void set_childOrientation(int _childOrientation) {
		this._childOrientation = _childOrientation;
	}

	public int get_currentLineType() {
		return _currentLineType;
	}

	public void set_currentLineType(int _currentLineType) {
		this._currentLineType = _currentLineType;
	}

	public int get_fatherId() {
		return _fatherId;
	}

	public void set_fatherId(int _fatherId) {
		this._fatherId = _fatherId;
	}

	public int get_childId() {
		return _childId;
	}

	public void set_childId(int _childId) {
		this._childId = _childId;
	}

	public int get_numberOfPoints() {
		return _numberOfPoints;
	}

	public void set_numberOfPoints(int _numberOfPoints) {
		this._numberOfPoints = _numberOfPoints;
	}

	public int get_fatherArrowType() {
		return _fatherArrowType;
	}

	public void set_fatherArrowType(int _fatherArrowType) {
		this._fatherArrowType = _fatherArrowType;
	}

	public int get_childArrowType() {
		return _childArrowType;
	}

	public void set_childArrowType(int _childArrowType) {
		this._childArrowType = _childArrowType;
	}

	public void set_fatherCenter(Point _fatherCenter) {
		this._fatherCenter = _fatherCenter;
	}

	public void setPointOfLine(int posX, int posY, int index) {
		try {
			if (_points[index] != null)
				_points[index].set(posX, posY);
			else
				_points[index] = new Point(posX, posY);
		} catch (Exception e) {

		}
	}

	public boolean checkOnTouch(Point touchPoint) {
		return false;
	}

	public void Dibujar(Canvas c, boolean isFcoused, float globalScale,
			int offSetX, int offSetY) {

		// Dibujamos las lineas del conector
		_linePath = getLinePaths(globalScale, offSetX, offSetY);
		switch (_currentLineType) {
		case DASHED_TYPE:
			c.drawPath(
					_linePath[0],
					Painter.getInstancia().getLineTypePaint(_currentState,
							DASHED_TYPE));
			c.drawPath(
					_linePath[1],
					Painter.getInstancia().getLineTypePaint(_currentState,
							DASHED_TYPE));
			break;

		case FATHER_SIDE_DASHED:
			c.drawPath(
					_linePath[0],
					Painter.getInstancia().getLineTypePaint(_currentState,
							DASHED_TYPE));
			c.drawPath(
					_linePath[1],
					Painter.getInstancia().getLineTypePaint(_currentState,
							NORMAL_TYPE));
			break;

		case CHILD_SIDE_DASHED:
			c.drawPath(
					_linePath[0],
					Painter.getInstancia().getLineTypePaint(_currentState,
							NORMAL_TYPE));
			c.drawPath(
					_linePath[1],
					Painter.getInstancia().getLineTypePaint(_currentState,
							DASHED_TYPE));
			break;

		default:
			c.drawPath(
					_linePath[0],
					Painter.getInstancia().getLineTypePaint(_currentState,
							NORMAL_TYPE));
			c.drawPath(
					_linePath[1],
					Painter.getInstancia().getLineTypePaint(_currentState,
							NORMAL_TYPE));
			break;
		}

		_normalLinePaint = Painter.getInstancia().getLineTypePaint(
				_currentState, NORMAL_TYPE);
		// Dibujamos la flecha del padre
		switch (_fatherArrowType) {
		/*
		 * case _arrowType.Asociacion:
		 * c.drawLine((_points[0].x+offSetX)*globalScale,
		 * (_points[0].y+offSetY)*globalScale,
		 * (_points[1].x+offSetX)*globalScale,
		 * (_points[1].y+offSetY)*globalScale, _normalLinePaint); break;
		 */
		case _arrowType.Herencia:
			dibujarHerencia(c, globalScale, new Point(
					(int) ((_points[0].x + offSetX) * globalScale),
					(int) ((_points[0].y + offSetY) * globalScale)), new Point(
					(int) ((_points[1].x + offSetX) * globalScale),
					(int) ((_points[1].y + offSetY) * globalScale)),
					_fatherOrientation);
			break;

		case _arrowType.Asociacion_Directa:
			dibujarAsociacionDirecta(c, globalScale, new Point(
					(int) ((_points[0].x + offSetX) * globalScale),
					(int) ((_points[0].y + offSetY) * globalScale)), new Point(
					(int) ((_points[1].x + offSetX) * globalScale),
					(int) ((_points[1].y + offSetY) * globalScale)),
					_fatherOrientation);
			break;

		case _arrowType.Composicion:
			dibujarComposicion(c, globalScale, new Point(
					(int) ((_points[0].x + offSetX) * globalScale),
					(int) ((_points[0].y + offSetY) * globalScale)), new Point(
					(int) ((_points[1].x + offSetX) * globalScale),
					(int) ((_points[1].y + offSetY) * globalScale)),
					_fatherOrientation, true);
			break;

		case _arrowType.Agregacion:
			dibujarComposicion(c, globalScale, new Point(
					(int) ((_points[0].x + offSetX) * globalScale),
					(int) ((_points[0].y + offSetY) * globalScale)), new Point(
					(int) ((_points[1].x + offSetX) * globalScale),
					(int) ((_points[1].y + offSetY) * globalScale)),
					_fatherOrientation, false);
			break;

		case _arrowType.PataDeGallo:
			dibujarPataDeGallo(c, globalScale, new Point(
					(int) ((_points[0].x + offSetX) * globalScale),
					(int) ((_points[0].y + offSetY) * globalScale)), new Point(
					(int) ((_points[1].x + offSetX) * globalScale),
					(int) ((_points[1].y + offSetY) * globalScale)),
					_fatherOrientation, false);
			break;

		case _arrowType.PataDeGallo_PK:
			dibujarPataDeGallo(c, globalScale, new Point(
					(int) ((_points[0].x + offSetX) * globalScale),
					(int) ((_points[0].y + offSetY) * globalScale)), new Point(
					(int) ((_points[1].x + offSetX) * globalScale),
					(int) ((_points[1].y + offSetY) * globalScale)),
					_fatherOrientation, true);
			break;

		default:
			break;
		}

		// Dibujamos la flecha del hijo
		switch (_childArrowType) {
		/*
		 * case _arrowType.Asociacion:
		 * c.drawLine((_points[_numberOfPoints-1].x+offSetX)*globalScale,
		 * (_points[_numberOfPoints-1].y+offSetY)*globalScale,
		 * (_points[_numberOfPoints-2].x+offSetX)*globalScale,
		 * (_points[_numberOfPoints-2].y+offSetY)*globalScale,
		 * _normalLinePaint); break;
		 */
		case _arrowType.Herencia:
			dibujarHerencia(
					c,
					globalScale,
					new Point(
							(int) ((_points[_numberOfPoints - 1].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 1].y + offSetY) * globalScale)),
					new Point(
							(int) ((_points[_numberOfPoints - 2].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 2].y + offSetY) * globalScale)),
					_childOrientation);
			break;

		case _arrowType.Asociacion_Directa:
			dibujarAsociacionDirecta(
					c,
					globalScale,
					new Point(
							(int) ((_points[_numberOfPoints - 1].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 1].y + offSetY) * globalScale)),
					new Point(
							(int) ((_points[_numberOfPoints - 2].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 2].y + offSetY) * globalScale)),
					_childOrientation);
			break;

		case _arrowType.Composicion:
			dibujarComposicion(
					c,
					globalScale,
					new Point(
							(int) ((_points[_numberOfPoints - 1].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 1].y + offSetY) * globalScale)),
					new Point(
							(int) ((_points[_numberOfPoints - 2].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 2].y + offSetY) * globalScale)),
					_childOrientation, true);
			break;

		case _arrowType.Agregacion:
			dibujarComposicion(
					c,
					globalScale,
					new Point(
							(int) ((_points[_numberOfPoints - 1].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 1].y + offSetY) * globalScale)),
					new Point(
							(int) ((_points[_numberOfPoints - 2].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 2].y + offSetY) * globalScale)),
					_childOrientation, false);
			break;

		case _arrowType.PataDeGallo:
			dibujarPataDeGallo(
					c,
					globalScale,
					new Point(
							(int) ((_points[_numberOfPoints - 1].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 1].y + offSetY) * globalScale)),
					new Point(
							(int) ((_points[_numberOfPoints - 2].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 2].y + offSetY) * globalScale)),
					_childOrientation, false);
			break;

		case _arrowType.PataDeGallo_PK:
			dibujarPataDeGallo(
					c,
					globalScale,
					new Point(
							(int) ((_points[_numberOfPoints - 1].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 1].y + offSetY) * globalScale)),
					new Point(
							(int) ((_points[_numberOfPoints - 2].x + offSetX) * globalScale),
							(int) ((_points[_numberOfPoints - 2].y + offSetY) * globalScale)),
					_childOrientation, true);
			break;

		default:
			break;
		}

		if (_fatherArrowType == _arrowType.Agregacion
				|| _fatherArrowType == _arrowType.Composicion
				|| _childArrowType == _arrowType.Agregacion
				|| _childArrowType == _arrowType.Composicion) {
			// Dibujamos la cardinalidad del padre
			dibujarCardinalidad(c, new Point(_points[0].x + offSetX,
					_points[0].y + offSetY), _fatherOrientation,
					_fatherCardenalityLeft, _fatherCardenalityRight,
					globalScale);

			// Dibujamos la cardinalidad del hijo
			dibujarCardinalidad(c, new Point(_points[_numberOfPoints - 1].x
					+ offSetX, _points[_numberOfPoints - 1].y + offSetY),
					_childOrientation, _childCardenalityLeft,
					_childCardenalityRight, globalScale);
		}
	}

	private int calcularDistTotal() {
		int respuesta = 0;
		for (int i = 0; i < _numberOfPoints - 1; i++) {
			respuesta += Math.hypot(_points[i].x - _points[i + 1].x,
					_points[i].y - _points[i + 1].y);
		}
		return respuesta;
	}

	private int calcularDistEntrePuntos(Point a, Point b) {
		int respuesta = (int) Math.hypot(a.x - b.x, a.y - b.y);
		return respuesta;
	}

	private Path[] getLinePaths(float globalScale, int offSetX, int offSetY) {
		Path[] respuesta = new Path[2];
		int midPoint = 0;
		int DistanciaMedia = calcularDistTotal() / 2;
		int DistAcum = 0;
		int DistActual;
		Point puntoMedio;
		respuesta[0] = new Path();
		respuesta[0].moveTo((_points[0].x + offSetX) * globalScale,
				(_points[0].y + offSetY) * globalScale);
		for (int i = 0; i < _numberOfPoints - 1; i++) {
			DistActual = calcularDistEntrePuntos(_points[i], _points[i + 1]);
			if (DistActual + DistAcum >= DistanciaMedia) {
				puntoMedio = new Point();
				puntoMedio
						.set((int) ((((_points[i + 1].x + _points[i].x) / 2) + offSetX) * globalScale),
								(int) ((((_points[i + 1].y + _points[i].y) / 2) + offSetY) * globalScale));
				respuesta[0].lineTo(puntoMedio.x, puntoMedio.y);
				respuesta[1] = new Path();
				respuesta[1].moveTo(puntoMedio.x, puntoMedio.y);
				midPoint = i + 1;
				break;
			} else {
				DistAcum += DistActual;
				respuesta[0].lineTo((_points[i + 1].x + offSetX) * globalScale,
						(_points[i + 1].y + offSetY) * globalScale);
			}
		}
		respuesta[1].lineTo((_points[midPoint].x + offSetX) * globalScale,
				(_points[midPoint].y + offSetY) * globalScale);
		for (int i = midPoint; i < _numberOfPoints - 1; i++) {
			respuesta[1].lineTo((_points[i + 1].x + offSetX) * globalScale,
					(_points[i + 1].y + offSetY) * globalScale);
		}
		return respuesta;
	}

	public void dibujarHerencia(Canvas c, float globalScale, Point begin,
			Point end, int orientation) {
		Path myPath = new Path();
		switch (orientation) {

		case ORIENTATION_TOP:
			myPath.moveTo(begin.x + (10 * globalScale), begin.y
					- (20 * globalScale));
			myPath.lineTo(begin.x, begin.y);
			myPath.lineTo(begin.x - (10 * globalScale), begin.y
					- (20 * globalScale));
			myPath.close();
			c.drawPath(myPath, Painter.getInstancia().getFillPaint());
			c.drawPath(myPath,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			break;
		case ORIENTATION_BOTTOM:
			myPath.moveTo(begin.x + (10 * globalScale), begin.y
					+ (20 * globalScale));
			myPath.lineTo(begin.x, begin.y);
			myPath.lineTo(begin.x - (10 * globalScale), begin.y
					+ (20 * globalScale));
			myPath.close();
			c.drawPath(myPath, Painter.getInstancia().getFillPaint());
			c.drawPath(myPath,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			break;

		case ORIENTATION_LEFT:
			myPath.moveTo(begin.x - (20 * globalScale), begin.y
					- (10 * globalScale));
			myPath.lineTo(begin.x, begin.y);
			myPath.lineTo(begin.x - (20 * globalScale), begin.y
					+ (10 * globalScale));
			myPath.close();
			c.drawPath(myPath, Painter.getInstancia().getFillPaint());
			c.drawPath(myPath,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			break;

		case ORIENTATION_RIGHT:
			myPath.moveTo(begin.x + (20 * globalScale), begin.y
					- (10 * globalScale));
			myPath.lineTo(begin.x, begin.y);
			myPath.lineTo(begin.x + (20 * globalScale), begin.y
					+ (10 * globalScale));
			myPath.close();
			c.drawPath(myPath, Painter.getInstancia().getFillPaint());
			c.drawPath(myPath,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			break;

		default:
			break;
		}
	}

	public void dibujarAsociacionDirecta(Canvas c, float globalScale,
			Point begin, Point end, int orientation) {

		switch (orientation) {

		case ORIENTATION_TOP:
			c.drawLine(begin.x, begin.y, begin.x + (10 * globalScale), begin.y
					- (20 * globalScale), _normalLinePaint);
			c.drawLine(begin.x, begin.y, begin.x - (10 * globalScale), begin.y
					- (20 * globalScale), _normalLinePaint);
			break;
		case ORIENTATION_BOTTOM:
			c.drawLine(begin.x, begin.y, begin.x + (10 * globalScale), begin.y
					+ (20 * globalScale), _normalLinePaint);
			c.drawLine(begin.x, begin.y, begin.x - (10 * globalScale), begin.y
					+ (20 * globalScale), _normalLinePaint);
			break;

		case ORIENTATION_LEFT:
			c.drawLine(begin.x, begin.y, begin.x - (20 * globalScale), begin.y
					+ (10 * globalScale), _normalLinePaint);
			c.drawLine(begin.x, begin.y, begin.x - (20 * globalScale), begin.y
					- (10 * globalScale), _normalLinePaint);
			break;

		case ORIENTATION_RIGHT:
			c.drawLine(begin.x, begin.y, begin.x + (20 * globalScale), begin.y
					- (10 * globalScale), _normalLinePaint);
			c.drawLine(begin.x, begin.y, begin.x + (20 * globalScale), begin.y
					+ (10 * globalScale), _normalLinePaint);
			break;
		default:

			break;
		}
	}

	public void dibujarComposicion(Canvas c, float globalScale, Point begin,
			Point end, int orientation, boolean isStrong) {
		Path myPath = new Path();
		switch (orientation) {

		case ORIENTATION_TOP:
			myPath.moveTo(begin.x + (12 * globalScale), begin.y
					- (15 * globalScale));
			myPath.lineTo(begin.x, begin.y);
			myPath.lineTo(begin.x - (12 * globalScale), begin.y
					- (15 * globalScale));
			myPath.lineTo(begin.x, begin.y - (30 * globalScale));
			myPath.close();
			if (isStrong) {
				c.drawPath(
						myPath,
						Painter.getInstancia().getArrowPaint(_currentState,
								true));
			} else {
				c.drawPath(myPath, Painter.getInstancia().getFillPaint());
				c.drawPath(
						myPath,
						Painter.getInstancia().getArrowPaint(_currentState,
								false));
			}
			break;
		case ORIENTATION_BOTTOM:
			myPath.moveTo(begin.x + (12 * globalScale), begin.y
					+ (15 * globalScale));
			myPath.lineTo(begin.x, begin.y);
			myPath.lineTo(begin.x - (12 * globalScale), begin.y
					+ (15 * globalScale));
			myPath.lineTo(begin.x, begin.y + (30 * globalScale));
			myPath.close();
			if (isStrong) {
				c.drawPath(
						myPath,
						Painter.getInstancia().getArrowPaint(_currentState,
								true));
			} else {
				c.drawPath(myPath, Painter.getInstancia().getFillPaint());
				c.drawPath(
						myPath,
						Painter.getInstancia().getArrowPaint(_currentState,
								false));
			}
			break;

		case ORIENTATION_LEFT:
			myPath.moveTo(begin.x - (15 * globalScale), begin.y
					- (12 * globalScale));
			myPath.lineTo(begin.x, begin.y);
			myPath.lineTo(begin.x - (15 * globalScale), begin.y
					+ (12 * globalScale));
			myPath.lineTo(begin.x - (30 * globalScale), begin.y);
			myPath.close();
			if (isStrong) {
				c.drawPath(
						myPath,
						Painter.getInstancia().getArrowPaint(_currentState,
								true));
			} else {
				c.drawPath(myPath, Painter.getInstancia().getFillPaint());
				c.drawPath(
						myPath,
						Painter.getInstancia().getArrowPaint(_currentState,
								false));
			}
			break;

		case ORIENTATION_RIGHT:
			myPath.moveTo(begin.x + (15 * globalScale), begin.y
					- (12 * globalScale));
			myPath.lineTo(begin.x, begin.y);
			myPath.lineTo(begin.x + (15 * globalScale), begin.y
					+ (12 * globalScale));
			myPath.lineTo(begin.x + (30 * globalScale), begin.y);
			myPath.close();
			if (isStrong) {
				c.drawPath(
						myPath,
						Painter.getInstancia().getArrowPaint(_currentState,
								true));
			} else {
				c.drawPath(myPath, Painter.getInstancia().getFillPaint());
				c.drawPath(
						myPath,
						Painter.getInstancia().getArrowPaint(_currentState,
								false));
			}
			break;

		default:
			break;
		}

	}

	protected void dibujarPataDeGallo(Canvas c, float globalScale, Point begin,
			Point end, int orientation, boolean isPK) {
		Path myPath = new Path();
		switch (orientation) {

		case ORIENTATION_TOP:
			c.drawLine(begin.x, begin.y, begin.x, begin.y - (15 * globalScale),
					Painter.getInstancia().getArrowPaint(_currentState, false));
			myPath.moveTo(begin.x - (12 * globalScale), begin.y);
			myPath.lineTo(begin.x, begin.y - (15 * globalScale));
			myPath.lineTo(begin.x + (12 * globalScale), begin.y);
			// myPath.close();
			c.drawPath(myPath,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			if (isPK) {
				c.drawLine(begin.x - (12 * globalScale), begin.y
						- (20 * globalScale), begin.x + (12 * globalScale),
						begin.y - (20 * globalScale), Painter.getInstancia()
								.getArrowPaint(_currentState, false));
			}
			break;
		case ORIENTATION_BOTTOM:
			c.drawLine(begin.x, begin.y, begin.x, begin.y + (15 * globalScale),
					Painter.getInstancia().getArrowPaint(_currentState, false));
			myPath.moveTo(begin.x - (12 * globalScale), begin.y);
			myPath.lineTo(begin.x, begin.y + (15 * globalScale));
			myPath.lineTo(begin.x + (12 * globalScale), begin.y);
			// myPath.close();
			c.drawPath(myPath,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			if (isPK) {
				c.drawLine(begin.x - (12 * globalScale), begin.y
						+ (20 * globalScale), begin.x + (12 * globalScale),
						begin.y + (20 * globalScale), Painter.getInstancia()
								.getArrowPaint(_currentState, false));
			}
			break;

		case ORIENTATION_LEFT:
			c.drawLine(begin.x, begin.y, begin.x - (15 * globalScale), begin.y,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			myPath.moveTo(begin.x, begin.y - (12 * globalScale));
			myPath.lineTo(begin.x - (15 * globalScale), begin.y);
			myPath.lineTo(begin.x, begin.y + (12 * globalScale));
			// myPath.close();
			c.drawPath(myPath,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			if (isPK) {
				c.drawLine(begin.x - (20 * globalScale), begin.y
						- (12 * globalScale), begin.x - (20 * globalScale),
						begin.y + (12 * globalScale), Painter.getInstancia()
								.getArrowPaint(_currentState, false));
			}
			break;

		case ORIENTATION_RIGHT:
			c.drawLine(begin.x, begin.y, begin.x + (15 * globalScale), begin.y,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			myPath.moveTo(begin.x, begin.y - (12 * globalScale));
			myPath.lineTo(begin.x + (15 * globalScale), begin.y);
			myPath.lineTo(begin.x, begin.y + (12 * globalScale));
			// myPath.close();
			c.drawPath(myPath,
					Painter.getInstancia().getArrowPaint(_currentState, false));
			if (isPK) {
				c.drawLine(begin.x + (20 * globalScale), begin.y
						- (12 * globalScale), begin.x + (20 * globalScale),
						begin.y + (12 * globalScale), Painter.getInstancia()
								.getArrowPaint(_currentState, false));
			}
			break;

		default:
			break;
		}

	}

	public void dibujarCardinalidad(Canvas c, Point anchor, int orientation,
			String M, String N, float globalScale) {
		String Cardinalidad = "";
		Paint textPaint = Painter.getInstancia().getTextPaint(false,
				globalScale);
		textPaint.setTextSize(15 * globalScale);
		try {
			if (N.equals("*")) {
				if (Integer.valueOf(M) == 1) {
					Cardinalidad = "*";
				} else {
					Cardinalidad = M + ".." + N;
				}
			} else {
				if (Integer.valueOf(M) == Integer.valueOf(N)) {
					Cardinalidad = M;
				} else {
					Cardinalidad = M + ".." + N;
				}
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		switch (orientation) {
		case ORIENTATION_TOP:
			c.drawText(Cardinalidad, (anchor.x + 7) * globalScale,
					(anchor.y - 25) * globalScale, textPaint);
			break;

		case ORIENTATION_BOTTOM:
			c.drawText(Cardinalidad, (anchor.x + 7) * globalScale,
					(anchor.y + 35) * globalScale, textPaint);
			break;

		case ORIENTATION_LEFT:
			c.drawText(Cardinalidad,
					(anchor.x - 30 - textPaint.measureText(Cardinalidad))
							* globalScale, (anchor.y - 7) * globalScale,
					textPaint);
			break;

		case ORIENTATION_RIGHT:
			c.drawText(Cardinalidad, (anchor.x + 30) * globalScale,
					(anchor.y - 7) * globalScale, textPaint);
			break;

		default:
			break;
		}
	}

	public void CalcularConexiones(Componente father, Componente child) {
		_fatherCenter = father.get_centerPoint();
		_childCenter = child.get_centerPoint();

		int Ax = father.Anchor.x;
		int AxWith = (int) (Ax + father.get_width());
		int Ay = father.Anchor.y;
		int AyHeight = (int) (Ay + father.get_width());
		// Ubicar Cuadrante
		
		if(_fatherCenter != _childCenter){
			_numberOfPoints = 4;
			_points[0] = father.requestConnectionPoint(this, 1, _childCenter);
			_points[3] = child.requestConnectionPoint(this, 2, _fatherCenter);
			calcularRutaIntermedia();
		}else{
			actualizarRuta(father);
		}
	}

	/*
	 * public void CalcularConexiones(Componente father, Componente child){
	 * _fatherCenter = father.get_centerPoint(); _childCenter =
	 * child.get_centerPoint();
	 * 
	 * int Ax = father.Anchor.x; int AxWith = (int) (Ax + father.get_width());
	 * int Ay = father.Anchor.y; int AyHeight = (int) (Ay + father.get_width());
	 * //Ubicar Cuadrante
	 * 
	 * if(child.get_centerPoint().y <= Ay){ //Cuadrantes Superiores if(Ax >
	 * child.get_centerPoint().x){// Cuadrante Derecho _childQuadrant = 8;
	 * _numberOfPoints = 3; _points[0] =
	 * father.get_topAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_TOP; _points[2] = child.get_rightAnchors().obtenerPosicion();
	 * _childOrientation = ORIENTATION_RIGHT; calcularRutaIntermedia(); }else if
	 * (child.get_centerPoint().x > AxWith){ //Cuadrante Izquierdo
	 * _childQuadrant = 2; _numberOfPoints = 3; _points[0] =
	 * father.get_topAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_TOP; _points[2] = child.get_leftAnchors().obtenerPosicion();
	 * _childOrientation = ORIENTATION_LEFT; calcularRutaIntermedia(); }else{
	 * _childQuadrant = 1; _numberOfPoints = 4; _points[0] =
	 * father.get_topAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_TOP; _points[3] =
	 * child.get_bottomAnchors().obtenerPosicion(); _childOrientation =
	 * ORIENTATION_BOTTOM; calcularRutaIntermedia(); } }else if(
	 * child.get_centerPoint().y >= AyHeight){//Cuadrantes Inferiores if(Ax >
	 * child.get_centerPoint().x){// Cuadrante Derecho _childQuadrant = 6;
	 * _numberOfPoints = 3; _points[0] =
	 * father.get_bottomAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_BOTTOM; _points[2] =
	 * child.get_rightAnchors().obtenerPosicion(); _childOrientation =
	 * ORIENTATION_RIGHT; calcularRutaIntermedia(); }else if
	 * (child.get_centerPoint().x > AxWith){ //Cuadrante Izquierdo
	 * _childQuadrant = 4; _numberOfPoints = 3; _points[0] =
	 * father.get_bottomAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_BOTTOM; _points[2] =
	 * child.get_leftAnchors().obtenerPosicion(); _childOrientation =
	 * ORIENTATION_LEFT; calcularRutaIntermedia(); }else{ _childQuadrant = 5;
	 * _numberOfPoints = 4; _points[0] =
	 * father.get_bottomAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_BOTTOM; _points[3] =
	 * child.get_topAnchors().obtenerPosicion(); _childOrientation =
	 * ORIENTATION_TOP; calcularRutaIntermedia(); } }else{//Cuadrantes Medios
	 * if(Ax > child.get_centerPoint().x){// Cuadrante Derecho _childQuadrant =
	 * 7; _numberOfPoints = 4; _points[0] =
	 * father.get_leftAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_LEFT; _points[3] =
	 * child.get_rightAnchors().obtenerPosicion(); _childOrientation =
	 * ORIENTATION_RIGHT; calcularRutaIntermedia(); }else if
	 * (child.get_centerPoint().x > AxWith){ //Cuadrante Izquierdo
	 * _childQuadrant = 3; _numberOfPoints = 4; _points[0] =
	 * father.get_rightAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_RIGHT; _points[3] =
	 * child.get_leftAnchors().obtenerPosicion(); _childOrientation =
	 * ORIENTATION_LEFT; calcularRutaIntermedia(); }else{ _childQuadrant = 0;
	 * _numberOfPoints = 2; _points[0] =
	 * father.get_leftAnchors().obtenerPosicion(); _fatherOrientation =
	 * ORIENTATION_INNER_LEFT; _points[1] =
	 * child.get_leftAnchors().obtenerPosicion(); _childOrientation =
	 * ORIENTATION_LEFT; } }
	 * 
	 * }
	 */
	public void actualizarRuta(Componente father) {
		if(_fatherId != _childId){
			int Ax = father.Anchor.x;
			int AxWith = (int) (Ax + father.get_width());
			int Ay = father.Anchor.y;
			int AyHeight = (int) (Ay + father.get_width());
	
			// Ubicar Cuadrante
			if (_fatherCenter == null) {
				_fatherCenter = VistaDiagrama.getVista().getDiagrama()
						.getComponenteById(_fatherId).get_centerPoint();
			}
			if (_childCenter == null) {
				_childCenter = VistaDiagrama.getVista().getDiagrama()
						.getComponenteById(_childId).get_centerPoint();
			}
	
			_numberOfPoints = 4;
			_points[0] = father.requestConnectionPoint(this, 1, _childCenter);
			_points[3] = VistaDiagrama.getVista().getDiagrama()
					.getComponenteById(_childId)
					.requestConnectionPoint(this, 2, _fatherCenter);
			calcularRutaIntermedia();
		}else{
			_numberOfPoints = 5;
			_points[0] = new Point((int) (father.Anchor.x + father.get_width()/3),father.Anchor.y);
			_points[1] = new Point((int) (father.Anchor.x + father.get_width()/3),father.Anchor.y-RECURSIVE_SPAN);
			_points[2] = new Point((int) (father.Anchor.x - RECURSIVE_SPAN),father.Anchor.y-RECURSIVE_SPAN);
			_points[3] = new Point((int) (father.Anchor.x - RECURSIVE_SPAN),father.Anchor.y+(int)(father.get_height()/3));
			_points[4] = new Point((int) (father.Anchor.x),father.Anchor.y+(int)(father.get_height()/3));
			_fatherOrientation = ORIENTATION_TOP;
			_childOrientation = ORIENTATION_LEFT;
		}
	}

	public void calcularRutaIntermedia() {
		switch (_numberOfPoints) {
		case 3:
			_points[1] = new Point(_points[0].x, _points[2].y);
			break;

		case 4:
			if (_fatherOrientation == ORIENTATION_LEFT
					|| _fatherOrientation == ORIENTATION_RIGHT) {
				int dist = (_points[3].x - _points[0].x) / 2;
				_points[1] = new Point((_points[0].x + dist), _points[0].y);
				_points[2] = new Point((_points[0].x + dist), _points[3].y);
			} else {
				int dist = (_points[3].y - _points[0].y) / 2;
				_points[1] = new Point((_points[0].x), _points[0].y + dist);
				_points[2] = new Point((_points[3].x), _points[0].y + dist);
			}
			break;

		default:
			break;
		}
	}

	public boolean calcularTouch(Point touch) {
		boolean respuesta = false;
		Point inter;
		for (int i = 0; i < _numberOfPoints - 1; i++) {
			if (calcularDist(_points[i], _points[i + 1], touch) <= TOUCH_HITBOX_SIZE) {
				inter = calcularPuntoInterseccion(_points[i], _points[i + 1],
						touch);
				respuesta = checkearPuntoEnSegmento(_points[i], _points[i + 1],
						inter);
			}
		}
		return respuesta;
	}

	private float calcularDist(Point lineStart, Point lineEnd, Point punto) {
		float respuesta = 0;
		if (lineEnd.x - lineStart.x == 0) { // Si la recta es VERTICAL
			respuesta = Math.abs(lineStart.x - punto.x); // Regresamos la
															// diferencia entre
															// las X
		} else if (lineEnd.y - lineStart.y == 0) {// Si la recta es HORIZONTAL
			respuesta = Math.abs(lineStart.y - punto.y); // Regresamos la
															// diferencia entre
															// las Y
		} else {// En caso de que la recta tenga una pendiente distinta de 0 o
				// infinita
			float m = (lineStart.y - punto.y) / (lineEnd.x - lineStart.x);
			float c = (m * lineStart.x - lineStart.y);
			respuesta = (float) (Math.abs((punto.x * -m) + punto.y + c) / Math
					.hypot(m, 1));
		}
		System.out.println("Calculo de distancia= " + respuesta);
		return respuesta;
	}

	private Point calcularPuntoInterseccion(Point lineStart, Point lineEnd,
			Point punto) {
		Point respuesta;
		if (lineEnd.x - lineStart.x == 0) { // Si la recta es VERTICAL
			respuesta = new Point(lineStart.x, punto.y);
		} else if (lineEnd.y - lineStart.y == 0) {// Si la recta es HORIZONTAL
			respuesta = new Point(punto.x, lineStart.y);
		} else {
			float m = (lineStart.y - punto.y) / (lineEnd.x - lineStart.x);
			float B1 = (-m * lineStart.x) + lineStart.y;
			float B2 = (punto.x / m) + punto.y;
			float x = (m * (B2 - B1)) / ((m * m) + 1);
			float y = (x * m) + B1;
			respuesta = new Point((int) x, (int) y);
		}
		return respuesta;
	}

	private boolean checkearPuntoEnSegmento(Point start, Point end, Point test) {
		boolean respuesta = false;
		int compX = (start.x - test.x) * (end.x - test.x);
		int compY = (start.y - test.y) * (end.y - test.y);
		if (compX <= 0 && compY <= 0) {
			if (compX * compY >= 0)
				respuesta = true;
		}
		return respuesta;
	}

	public void setState(int State) {
		_currentState = State;
	}

	public String generarDOM() {
		String DOM = "\t<Conector IDPadre=\"" + _fatherId + "\" IDHijo=\""
				+ _childId + "\" CuadranteHijo=\"" + _childQuadrant
				+ "\" FlechaPadre=\"" + _fatherArrowType + "\" FlechaHijo=\""
				+ _childArrowType + "\" OrientacionPadre=\""
				+ _fatherOrientation + "\" OrientacionHijo=\""
				+ _childOrientation + "\" TipoLinea=\"" + _currentLineType
				+ "\">\n";
		DOM = DOM + "\t\t<Cardinalidad PadreIzq=\"" + _fatherCardenalityLeft
				+ "\" PadreDer=\"" + _fatherCardenalityRight + "\" HijoIzq=\""
				+ _childCardenalityLeft + "\" HijoDer=\""
				+ _childCardenalityRight + "\" />\n";
		for (int i = 0; i < _numberOfPoints; i++) {
			DOM = DOM + "\t\t<Punto X=\"" + _points[i].x + "\" Y=\""
					+ _points[i].y + "\" />\n";
		}
		DOM = DOM + "\t</Conector>\n";
		return DOM;
	}
}
